﻿using System;
using System.Collections.Generic;
using Myotragus.Data.Domain;
using Myotragus.Data.Util;

namespace Myotragus.Data.Containers
{
	public class EntitiesRegistrar : IEntitiesRegistrar
	{
		protected readonly IDictionary<Type, Type> DicTypeRegistry = new Dictionary<Type, Type>();

		#region Implementation of IEntitiesContainer

		public TEntity Create<TEntity>() where TEntity : IEntity
		{
			return (TEntity)Create(typeof(TEntity));
		}

		public IEntity Create(Type tEntity)
		{
			return (IEntity)Activator.CreateInstance(ResolveType(tEntity));
		}

		public TEntity Create<TEntity>(object prototype)
			where TEntity : IEntity
		{
			return (TEntity)Create(typeof(TEntity), prototype);
		}

		public IEntity Create(Type tEntity, object prototype)
		{
			var entity = Create(tEntity);
			ReflectionHelper.InitializeObject(entity, prototype);

			return entity;
		}

		public Type ResolveType(Type @interface)
		{
			if (!DicTypeRegistry.ContainsKey(@interface))
				throw new CannotResolveTypeException(@interface.ToString());

			return DicTypeRegistry[@interface];
		}

		public IEnumerable<Type> Interfaces
		{
			get { return DicTypeRegistry.Keys; }
		}

		#endregion Implementation of IEntitiesContainer

		#region Implementation of ITypeRegistrar

		public ITypeRegistrar RegisterFor(Type implementation, IEnumerable<Type> interfaces)
		{
			foreach (var ifc in interfaces)
				DicTypeRegistry[ifc] = implementation;

			return this;
		}

		public ITypeRegistrar RegisterFor(Type implementation, params Type[] interfaces)
		{
			return RegisterFor(implementation, (IEnumerable<Type>)interfaces);
		}

		public ITypeRegistrar RegisterForAll(params Type[] implementations)
		{
			return RegisterForAll((IEnumerable<Type>)implementations);
		}

		public ITypeRegistrar RegisterForAll(IEnumerable<Type> implementations)
		{
			foreach (var imp in implementations)
				RegisterFor(imp, imp.GetInterfaces());

			return this;
		}

		public ITypeRegistrar RegisterForDefault(params Type[] implementations)
		{
			return RegisterForDefault((IEnumerable<Type>)implementations);
		}

		public ITypeRegistrar RegisterForDefault(IEnumerable<Type> implementations)
		{
			foreach (var imp in implementations)
				RegisterFor(imp, ReflectionHelper.GetDefaultInterface(imp));

			return this;
		}

		#endregion Implementation of ITypeRegistrar
	}
}